using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using System.Management;

using DataAccessLayer;

namespace MirroringFailover
{
    public partial class Form1 : Form
    {
        private DAL dal = new DAL();
        private bool stopping;
        private int connectFailures = 0, disconnectFailures = 0, workFailures = 0;
        private int count = 0;
        Stopwatch failoverTimer = new Stopwatch();

        public Form1()
        {
            InitializeComponent();
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            if (dal.Connect(txtPrincipal.Text, txtMirror.Text, cbTrackChanges.Checked, true) >= 0)
            {
                txtActualPrincpial.Text = dal.ActualPrincipal;
                txtActualPartner.Text = dal.ActualPartner;
                btnConnect.Enabled = false;
                btnDisconnect.Enabled = true;
                cbTrackChanges.Enabled = false;
                btnInitializeTable.Enabled = false;
                btnSingleThreadedTest.Enabled = false;
                if (dal.Count > 0)
                {
                    btnCommit.Enabled = true;
                    btnUpdate.Enabled = true;
                }
            }
            else
            {
                txtActualPrincpial.Text = "";
                txtActualPartner.Text = "";
            }
        }

        private void btnUpdate_Click(object sender, EventArgs e)
        {
            dal.Update(true);
            txtCount.Text = dal.Count.ToString();
        }

        private void btnCommit_Click(object sender, EventArgs e)
        {
            dal.Commit(true);
            txtCount.Text = dal.Count.ToString();
        }

        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            dal.Disconnect(true);
            if (cbTrackChanges.Checked)
            {
                txtPrincipal.Text = txtActualPrincpial.Text;
                txtMirror.Text = txtActualPartner.Text;
            }
            txtActualPrincpial.Text = "";
            txtActualPartner.Text = "";
            btnConnect.Enabled = true;
            btnDisconnect.Enabled = false;
            cbTrackChanges.Enabled = true;
            btnCommit.Enabled = false;
            btnUpdate.Enabled = false;


            if (dal.Count == 0)
            {
                btnInitializeTable.Enabled = true;
            }
            else
            {
                btnSingleThreadedTest.Enabled = true;
            }

            txtCount.Text = dal.Count.ToString();
        }

        private void btnSingleThreadedTest_Click(object sender, EventArgs e)
        {
            stopping = false;
            btnStop.Enabled = true;
            btnSingleThreadedTest.Enabled = false;

            if (failoverTimer.IsRunning) {
                failoverTimer.Start();
            }
            failoverTimer.Reset();

            backgroundWorker.RunWorkerAsync();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            stopping = true;
        }

        private void SingleThreadedTest()
        {
            int r;

            connectFailures = 0; disconnectFailures = 0; workFailures = 0;
            int connectRetries = 0, transactionRetries = 0;

            do {
                r = dal.Connect(txtPrincipal.Text, txtMirror.Text, true, false);
                if (r < 0) {
                    if (connectRetries == 0)
                    {
                        connectFailures++;
                        backgroundWorker.ReportProgress(0);
                    }
                    connectRetries++;
                    if (connectRetries <= 3)
                    {
                        continue;
                    }
                    else
                    {
                        MessageBox.Show("Could not connect in 3 re-tries, abandoning test", "MirroringFailover Explorer");
                        return;
                    }
                }

                if (failoverTimer.IsRunning)
                {
                    failoverTimer.Stop();
                    backgroundWorker.ReportProgress(2);

                }
                connectRetries = 0;

                r = dal.DoSomeWork();
                
                if (r < 0)
                {
                    if (transactionRetries <= 3)
                    {
                        workFailures++;
                        transactionRetries++;
                        backgroundWorker.ReportProgress(0);
                        dal.Disconnect(false);
                        continue;
                    }
                    else
                    {
                        MessageBox.Show("Could not complete transaction in 3 re-tries, abandoning test", "MirroringFailover Explorer");
                        return;
                    }
                }

                count = dal.Count;
                backgroundWorker.ReportProgress(1);
                transactionRetries = 0;


                r = dal.Disconnect(false);
                if (r < 0) {
                    disconnectFailures++;
                    backgroundWorker.ReportProgress(0);
                }
            } while (!stopping);
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            SingleThreadedTest();
        }

        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            switch (e.ProgressPercentage)
            {
                case 0:
                    txtConnectFailures.Text = connectFailures.ToString();
                    txtDisconnectFailures.Text = disconnectFailures.ToString();
                    txtWorkFailures.Text = workFailures.ToString();
                    if (txtLastError.Text == "")
                    {
                        txtLastError.Text = dal.lastSqlState;
                        txtLastMessage.Text = dal.lastErrorMessage;
                        txtLastNativeError.Text = dal.lastNativeError.ToString();
                    }
                    break;

                case 1:
                    txtCount.Text = count.ToString();
                    break;

                case 2:
                    txtActualPrincpial.Text = dal.ActualPrincipal;
                    txtActualPartner.Text = dal.ActualPartner;
                    txtFailoverTime.Text = failoverTimer.Elapsed.ToString();
                    failoverTimer.Reset();
                    break;
            }

        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            btnStop.Enabled = false;
            btnSingleThreadedTest.Enabled = true;

        }

        private void btnFailover_Click(object sender, EventArgs e)
        {
            int r;

            DAL failoverMDA = new DAL();
            r = failoverMDA.Connect(txtPrincipal.Text, txtMirror.Text, false, true);
            if (r >= 0)
            {
                btnFailover.Enabled = false;


                r = failoverMDA.MirroringFailover();

                if (r >= 0)
                {
                    txtLastError.Text = "";
                    txtLastMessage.Text = "";
                    txtLastNativeError.Text = "";
                    txtFailoverTime.Text = "";
                    failoverTimer.Start();
                }

                btnFailover.Enabled = true;
            }
            failoverMDA.Disconnect(false);
        }

        private void btnInitializeTable_Click(object sender, EventArgs e)
        {
            int r = dal.Connect(txtPrincipal.Text, txtMirror.Text, false, true);
            if (r < 0) return;

            r = dal.InitTable();
            if (r < 0)
            {
                dal.Disconnect(true);
                return;
            }

            dal.Disconnect(true);

            btnInitializeTable.Enabled = false;
            btnSingleThreadedTest.Enabled = true;
            txtCount.Text = dal.Count.ToString();
        }

        private void btnUpdateAlias_Click(object sender, EventArgs e)
        {
            btnUpdateAlias.Enabled = false;
            DAL da = new DAL();
            if (da.Connect(txtPrincipal.Text, txtMirror.Text, true, true) >= 0)
            {
                try
                {
                    ManagementScope scope = new ManagementScope(@"\\" + txtClient.Text + @"\root\Microsoft\SqlServer\ComputerManagement10");
                    ManagementObjectCollection clientAliases =
                        new ManagementClass(scope, new ManagementPath("SqlServerAlias"), null).GetInstances();

                    foreach (ManagementObject alias in clientAliases)
                    {
                        string aliasName = (string)alias["AliasName"];
                        if (aliasName == "ActiveServer")
                        {
                            alias["ServerName"] = da.ActualPrincipal;
                            // Commit changes to the server alias on the client
                            alias.Put();
                            txtAlias.Text = (string)alias["ServerName"];
                            break;
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error updating client configuration: " + ex.Message, "MirroringFailover Explorer");
                }

                da.Disconnect(true);
            }
            else
            {
                MessageBox.Show("Could not connect to server, please try again later", "MirroringFailover Explorer");
            }
            btnUpdateAlias.Enabled = true;
        }

        private void btnCheckAlias_Click(object sender, EventArgs e)
        {
            btnCheckAlias.Enabled = false;
            try
            {
                ManagementScope scope = new ManagementScope(@"\\" + txtClient.Text + @"\root\Microsoft\SqlServer\ComputerManagement");
                ManagementObjectCollection serverAliases =
                    new ManagementClass(scope, new ManagementPath("SqlServerAlias"), null).GetInstances();

                foreach (ManagementObject serverAlias in serverAliases)
                {
                    string aliasName = (string)serverAlias["AliasName"];
                    if (aliasName == "ActiveServer")
                    {
                        txtAlias.Text = (string)serverAlias["ServerName"]; ;
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error getting client configuration: " + ex.Message, "MirroringFailover Explorer");
            }
            btnCheckAlias.Enabled = true;
		}
    }
}